/*
 *
 * Created by yuri at Apr 2, 2011
 *
 */



package implementation.server;

import java.util.Collection;

import implementation.shared.EPacketParam;
import implementation.shared.EPacketType;
import implementation.shared.IPacket;
import implementation.shared.SharedFactory;
import implementation.shared.stubs.IPostStub;
import implementation.shared.stubs.IThreadStub;
import implementation.shared.stubs.IUserStub;

public class Session implements ISession{

	private static final String MESSAGE_LOGGED_OUT_SUCCESSFULLY = "Logged out successfully.";
	private static final String MESSAGE_USER_LOGGED_IN = "User already logged in.";
	private static final String MESSAGE_USER_NOT_LOGGEN_IN = "User not logged in.";
	
	
	private IConnection _connection;
	private IServer _system;
	private boolean _loggedin;
	private int _userID = -1;
	private int _currentThread = -1;

	public Session(IConnection connection, IServer system) {
		this._connection = connection;
		this._system = system;
	}

	@Override
	public IPacket handlePacket(IPacket packet) {
		IPacket answer = null;
		switch (packet.getType()) {
			case ELogin: {
				answer = this.handleLogin(packet);
				break;
			}
			case ERegister: {
				answer = this.handleRegister(packet);
				break;
			}
			case ELogout: {
				answer = this.handleLogout(packet);
				break;
			}
			case EGetAllForums: {
				answer = this.handleGetAllForums(packet);
				break;
			}
			case EGetAllThreads: {
				answer = this.handleGetAllThreads(packet);
				break;
			}
			case EGetAllPosts: {
				answer = this.handleGetAllPosts(packet);
				break;
			}
			case EAddPost: {
				answer = this.handleAddPost(packet);
				break;
			
			}
			case EEditPost: {
				answer = this.handleEditPost(packet);
				break;
			}
			case EAddThread: {
				answer = this.handleAddThread(packet);
				break;
			}
			case EGetFriends: {
				answer = this.handleGetFriends(packet);
				break;
			}
			case EGetPost: {
				answer = this.handleGetPost(packet);
				break;
			}
			case EGetThread: {
				answer = this.handleGetThread(packet);
				break;
			}
			case EGetForum: {
				answer = this.handleAddForum(packet);
				break;
			}
			case EAddFriend: {
				answer = this.handleAddFriend(packet);
				break;
			}
			case ERemoveThread: {
				answer = this.handleRemoveThread(packet);
				break;
			}
			case ERemoveFriend: {
				answer = this.handleRemoveFriend(packet);
				break;
			}
			case ERemovePost: {
				answer = this.handleRemovePost(packet);
				break;
			}
			default: {
				throw new UnsupportedOperationException();
			}
		}
		return answer;
	}
	
	// some of these need to be refactored so that the system doesn't need to handle or create IPackets.

	private IPacket handleRemovePost(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		int postID = (Integer)packet.getParam(EPacketParam.EID);
		if (this._system.removePost(this._userID,postID)) {
			return ServerFactory.createSuccessPacket("Removed post.");
		}
		String errorMsg = this._system.getLastError();
		return ServerFactory.createFailPacket(errorMsg);
	}

	private IPacket handleRemoveFriend(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		int friendID = (Integer)packet.getParam(EPacketParam.EID);
		if (this._system.removeFriend(this._userID,friendID)) {
			return ServerFactory.createSuccessPacket("Removed friend.");
		}
		String errorMsg = this._system.getLastError();
		return ServerFactory.createFailPacket(errorMsg);
	}

	private IPacket handleRemoveThread(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		int threadID = (Integer)packet.getParam(EPacketParam.EID);
		if (this._system.removeThread(this._userID,threadID)) {
			return ServerFactory.createSuccessPacket("Removed Thread.");
		}
		String errorMsg = this._system.getLastError();
		return ServerFactory.createFailPacket(errorMsg);
	}

	private IPacket handleGetAllPosts(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		int threadID = (Integer) packet.getParam(EPacketParam.EID);
		Collection<IPostStub> threadStubs = this._system.getAllPosts(threadID);
		if (threadStubs == null) {
			return ServerFactory.createFailPacket(this._system.getLastError());
		}
		IPacket answer = SharedFactory.createPacket(EPacketType.EGetAllPosts);
		answer.addParam(EPacketParam.ECollection, threadStubs);
		return answer;
	}

	private IPacket handleGetAllThreads(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		int forumID = (Integer) packet.getParam(EPacketParam.EID);
		Collection<IThreadStub> threadStubs = this._system.getAllThreads(forumID);
		if (threadStubs == null) {
			return ServerFactory.createFailPacket(this._system.getLastError());
		}
		IPacket answer = SharedFactory.createPacket(EPacketType.EGetAllThreads);
		answer.addParam(EPacketParam.ECollection, threadStubs);
		return answer;
	}

	private IPacket handleAddForum(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		String forumName = (String) packet.getParam(EPacketParam.ETopic);
		if (this._system.addForum(this._userID, forumName)) {
			return ServerFactory.createSuccessPacket("New Forum created.");
		}
		String errorMsg = this._system.getLastError();
		return ServerFactory.createFailPacket(errorMsg);
	}

	private IPacket handleGetThread(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		int threadID = (Integer) packet.getParam(EPacketParam.EID);
		IThreadStub threadStub = this._system.getThread(threadID);
		if (threadStub == null) {
			return ServerFactory.createFailPacket(this._system.getLastError());
		}
		this._currentThread = threadID;
		IPacket answer = SharedFactory.createPacket(EPacketType.EGetThread);
		answer.addParam(EPacketParam.EThread, threadStub);
		return answer;
	}

	private IPacket handleGetPost(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		int postID = (Integer) packet.getParam(EPacketParam.EID);
		IPostStub postStub = this._system.getPost(postID);
		if (postStub == null) {
			return ServerFactory.createFailPacket(this._system.getLastError());
		}
		IPacket answer = SharedFactory.createPacket(EPacketType.EGetPost);
		answer.addParam(EPacketParam.EPost, postStub);
		return answer;
	}

	private IPacket handleGetFriends(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		Collection<IUserStub> userStubs = this._system.getFriends(this._userID);
		if (userStubs == null) {
			return ServerFactory.createFailPacket(this._system.getLastError());
		}
		IPacket answer = SharedFactory.createPacket(EPacketType.EGetFriends);
		answer.addParam(EPacketParam.ECollection, userStubs);
		return answer;
	}

	private IPacket handleAddThread(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		String topic = (String) packet.getParam(EPacketParam.ETopic);
		String content = (String) packet.getParam(EPacketParam.EContent);
		int forumID = (Integer) packet.getParam(EPacketParam.EID);
		
		if (this._system.addThread(this._userID,forumID,topic,content)) {
			return ServerFactory.createSuccessPacket("New Thread created.");
		}
		String errorMsg = this._system.getLastError();
		return ServerFactory.createFailPacket(errorMsg);
	}

	private IPacket handleEditPost(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		String topic = (String) packet.getParam(EPacketParam.ETopic);
		String content = (String) packet.getParam(EPacketParam.EContent);
		int postID = (Integer) packet.getParam(EPacketParam.EID);
		
		if (this._system.editPost(this._userID,postID,topic,content)) {
			return ServerFactory.createSuccessPacket("Post edited.");
		}
		String errorMsg = this._system.getLastError();
		return ServerFactory.createFailPacket(errorMsg);
	}

	private IPacket handleAddPost(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		String topic = (String) packet.getParam(EPacketParam.ETopic);
		String content = (String) packet.getParam(EPacketParam.EContent);
		int threadID = (Integer) packet.getParam(EPacketParam.EID);
		
		if (this._system.addPost(this._userID,threadID,topic,content)) {
			return ServerFactory.createSuccessPacket("New Post created.");
		}
		String errorMsg = this._system.getLastError();
		return ServerFactory.createFailPacket(errorMsg);
	}

	private IPacket handleAddFriend(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		String friendName = (String) packet.getParam(EPacketParam.EUsername);
		IPacket answer = this._system.addFriend(this._userID,friendName);
		return answer;
	}

	private IPacket handleGetAllForums(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		IPacket answer = this._system.getAllForums();
		return answer;
	}

	private IPacket handleLogout(IPacket packet) {
		if (!this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_NOT_LOGGEN_IN);
		}
		IPacket answer = ServerFactory.createSuccessPacket(MESSAGE_LOGGED_OUT_SUCCESSFULLY);
		this._loggedin = false;
		return answer;
	}

	private IPacket handleRegister(IPacket packet) {
		if (this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_LOGGED_IN);
		}
		String username = (String) packet.getParam(EPacketParam.EUsername);
		String password = (String) packet.getParam(EPacketParam.EPassword);
		IPacket answer = this._system.register(username, password);
		if (answer.isSuccessful()) {
			this._userID = this._system.getUserID(username);
			this._loggedin = true;
		}
		return answer;
		
	}

	private IPacket handleLogin(IPacket packet) {
		if (this._loggedin) {
			return ServerFactory.createFailPacket(MESSAGE_USER_LOGGED_IN);
		}
		String username = (String) packet.getParam(EPacketParam.EUsername);
		String password = (String) packet.getParam(EPacketParam.EPassword);
		IPacket answer = this._system.validate(username, password);
		if (answer.isSuccessful()) {
			this._userID = this._system.getUserID(username);
			this._loggedin = true;
		}
		return answer;
	}



	@Override
	public boolean isLoggedIn() {
		return this._loggedin;
	}

	@Override
	public boolean send(IPacket packet) {
		return this._connection.send(packet);
	}

	@Override
	public void close() {
		this._connection.close();
	}

	@Override
	public int getUserID() {
		return this._userID;
	}

	@Override
	public int getCurrentThreadID() {
		return this._currentThread;
	}

}
